#include <stdio.h>

#include "Base.h"
#include "GraphicsEngine.h"
#include "Files.h"
#include "Level.h"
#include "SceneObject.h"

string Engine::programName;
using namespace std;

bool runProgram = true;

int main(int argc, char* argv[]){
	Engine::programName = "Cogs Engine";
	SDL_Event kevent; // for all keyboard inputs
	Engine::LoadControls();

	// set up the renderer
	gfx::Initialise();
	gfx::SetBackgroundColour(Colour(0.1f, 0.1f, 0.1f, 1.0f));
	World::BuildLevel();

	// Game loop
	while (runProgram){

		//!!!!!!!!!!!
		// todo:
		// unload textures that are not being used
		//!!!!!!!!!!!

		Engine::PollEvents(&kevent);
		Engine::DoDraw();
		Engine::DoThink();
		
		gfx::SwapBuffers();
	}
	gfx::DestroyRenderer();
	return 0;
}

void Engine::ThrowError(string msg){
	msg.insert(0, "Engine Error: ");
	const SDL_MessageBoxButtonData buttons[] = {
		{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 0, "Okay" }
	};
	const SDL_MessageBoxColorScheme colorScheme = {
		{
			{ 255, 0, 0 },
			{ 0, 255, 0 },
			{ 255, 255, 0 },
			{ 0, 0, 255 },
			{ 255, 0, 255 }
		}
	};
	const SDL_MessageBoxData messageBoxData = {
		SDL_MESSAGEBOX_INFORMATION,
		NULL,
		"Engine Error",
		msg.c_str(),
		SDL_arraysize(buttons),
		buttons,
		&colorScheme
	};
	int bId;
	if (SDL_ShowMessageBox(&messageBoxData, &bId) < 0) {
		ForceQuit();
	}else{
		ForceQuit();
	}
}

void Engine::QuitProgram(){
	runProgram = false;
}

void Engine::ForceQuit(){
	gfx::DestroyRenderer();
	std::terminate();
}

void Engine::LoadControls(){
	list<string> input = Configs::GetConfig("controls.cfg");
	Engine::LogError("Sucessfully Loaded Controls", Engine::errorType::TYPE_INFO);
}

void Engine::LogError(string error, errorType type){

	FileBuffer file("Logs\\engine.log");

	switch (type){
	case TYPE_INFO:
		error.insert(0, "INFO: ");
		break;
	case TYPE_WARNING:
		error.insert(0, "WARNING: ");
		break;
	case TYPE_ERROR:
		error.insert(0, "ERROR: ");
		break;
	case TYPE_FATAL:
		error.insert(0, "FATAL: ");
		break;
	}

	time_t cTime;
	struct tm * timeinfo;
	time(&cTime);
	timeinfo = localtime(&cTime);
	error.insert(0, asctime(timeinfo));

	if (!file.Append("\n"+error)){
		Engine::ThrowError("Unable to log error to error log.");
	}
}

void Engine::DoDraw(){
	list<SceneObject*>::iterator it = World::sceneObjects.begin();
	
	while (it != World::sceneObjects.end()){
		if (!(*it)->GetMaterial()->IsTransparent()){
			if ((*it)->GetProperties().nocull){
				glDisable(GL_CULL_FACE);
			}else{
				glEnable(GL_CULL_FACE);
			}
			
			(*it)->Draw();
		}
		++it;
	}
	
	//while (it != World::sceneObjects.end()){
	//	if ((*it)->GetMaterial->IsTransparent()){
	//		(*it)->Draw();
	//	}
	//}
}

void Engine::DoThink(){

}

void Engine::PollEvents(SDL_Event* kevent){
	while (SDL_PollEvent(kevent)){
		if (kevent->type == SDL_QUIT)
		{
			QuitProgram();
		}
	}
}